/**
********************************************************************************
@file     signal_linked_list.h
@brief    单向链表的头文件
@details
定义了单向链表相关的数据类型，并且定义了对单向链表进行操作的宏，
声明了对单向链表进行操作的函数的原型。
使用的时候，导入本头文件即可得到对单向链表进行操作的所有信息。
@author   jcai
@date     2021-05-11 09:02:36
@version  v0.2.2

\n Email:  wy1107412334@163.com
\n Blog:   None
\n Github: https://github.com/wy1107412334
\n Gitee:  https://gitee.com/git.git1107412334.com

********************************************************************************
@note
None.
********************************************************************************
@attention
None.
********************************************************************************
@verbatim
@endverbatim
********************************************************************************
@par 修订记录
- jcai, 2024-09-08
  - 从 data_structure 工程中 signal_link_list.h 移动而来
  - 移除一些使用不到的函数
  - 每个函数名数据类型名增加前缀 ut_
- jcai, 2024-09-08
  - 移除函数sllist_traverse()
- jcai, 2024-09-06
  - 修改了一些函数的原型
- jcai, 2024-09-04
  - 修改注释格式
- jcai, 2024-09-03
  - 重命名 sllist_destroy() 为 sllist_cleanup()
- jcai, 2024-09-03
  - 增加宏 ALLOC_EN 来使能需要malloc()/free()支持的功能
  - 修改注释说明
- jcai, 2023-07-05 11:01
  - 修复宏 SL_FOREACH 的遍历节点遍历需要依赖外部遍历的问题。
- jcai, 2021年8月3日 10点24分
  - 完善doxygen注释格式
- jcai, 2021年7月9日 11点15分
  - 修改doxygen的简要注释的格式
  - 给宏加上注释
  - 链表头新增一个长度字段
- jcai, 2021年6月29日 02点01分
  - 新增销毁链表的函数原型
  - 修复宏问题
- jcai, 2021年5月31日 13点32分
  - 定义枚举值用于函数的错误码
  - 定义遍历链表的宏
- jcai, 2021年5月19日 19点07分
  - 修改寻找链表中指定节点的函数及其回调函数的参数表
- jcai, 2021年5月17日 13点46分
  - 新增函数原型和修复宏定义错误
  - 删除行末多余空白字符
- jcai，2021-05-11 09:02:36
  - 首次编写

<center>Copyright &copy; 2021, 2023-2024 wy1107412334@163.com All rights reserved</center>
********************************************************************************
*/

#ifndef __SIGNAL_LINKED_LIST_H__
#define __SIGNAL_LINKED_LIST_H__


/* 头文件导入区 ------------------------------------------------------------- */

#include <stdint.h>
#include <stdio.h>


#ifdef __cplusplus
extern "C"
{
#endif

/** @addtogroup SIGNAL_LINKED_LIST
 * @{
 */


/* 条件编译定义 ------------------------------------------------------------- */





/* 模块输入API接口。即对外部少量依赖模块的API接口 --------------------------- */





/* 全局宏定义 --------------------------------------------------------------- */

/** @def UT_SLLIST_INIT(sl)
链表初始化

@param [out] sl: 指向链表头的指针
*/
#define UT_SLLIST_INIT(sl) (sl)->head=NULL, (sl)->tail=NULL, (sl)->length = 0

/** @def UT_DEFINE_SLLIST(name)
定义链表并初始化

@param name: 链表变量名
*/
#define UT_DEFINE_SLLIST(name) UT_SL_LIST name = {0}

/** @def UT_SL_FIRST_NODE(psl)
获取链表第一个节点的地址

@param [in] psl: 指向链表头的指针
@return 链表头节点的地址
*/
#define UT_SL_FIRST_NODE(psl)  (psl)->head
/** @def UT_SL_NEXT_NODE(pnode)
获取链表下一个节点的地址

@param [in] pnode: 指向链表中节点的指针
@return 下一个节点的地址
*/
#define UT_SL_NEXT_NODE(pnode) (pnode)->next
/** @def UT_SL_LAST_NODE(psl)
获取链表最后一个节点的地址

@param [in] psl: 指向链表头的指针
@return 链表尾节点的地址
*/
#define UT_SL_LAST_NODE(psl)   (psl)->tail
/** @def UT_SL_FOREACH(node, list)
链表遍历

@param [in] node: SL_NODE类型的局部指针变量名，仅在循环内部定义与使用。
                  用于依次指向链表 list 中的每个节点
@param [in] list: 指向链表头的指针
*/
#define UT_SL_FOREACH(node, list) \
    for (UT_SL_NODE *node = (list)->head; node; node = node->next)




/* 全局数据类型定义 --------------------------------------------------------- */

/** @enum ut_sl_err
链表返回的负值错误码及其含义
*/
enum ut_sl_err {
    UT_SL_ERR_ARGS     = -1,   /*!< 输入参数有误 */
    UT_SL_ERR_NOTEMPTY = -2,   /*!< 链表非空 */
    UT_SL_ERR_ISEXIST  = -3,   /*!< 节点存在链表中 */
    UT_SL_ERR_NOTEXIST = -4,   /*!< 节点不存在链表中 */
    UT_SL_ERR_INDEX    = -5,   /*!< 节点索引超出链表范围 */
    UT_SL_ERR_ISEMPTY  = -6,   /*!< 链表为空 */
};

/** @struct ut_sl_node
链表节点

保存下一个节点的地址
*/
typedef struct ut_sl_node {
    struct ut_sl_node    *next;    /*!< 指向下一个节点的指针 */
} UT_SL_NODE;                      /*!< 结构体 struct sl_node 的别名 */

/** @struct UT_SL_LIST
链表表头

链表表头中保存了链表的头节点和尾节点地址。
通过本数据结构可以完整描述一个链表。
*/
typedef struct {
    UT_SL_NODE     *head;          /*!< 指向链表头节点的指针 */
    UT_SL_NODE     *tail;          /*!< 指向链表尾节点的指针 */
    uint32_t     length;        /*!< 链表中节点的数量，即链表长度 */
} UT_SL_LIST;

/**
用于清空链表的回调函数的原型

本函数一般用于释放节点 node 指向的内存空间的

@param [in] node: 指向链表中的一个节点
*/
typedef void (*ut_sl_trav_callback)(const UT_SL_NODE *node);

/**
用于获取链表中指定节点的地址的回调函数的原型

本函数一般用于想要获取存在某个数据的节点的地址。

@param [in] node: 指向链表中的一个节点的指针
@param [in] arg: 用户传入的参数
@return 如果节点 node 是想寻找的节点，则返回非0值；否则返回0
@note 不建议在此函数中修改 node 指向的节点的数据
*/
typedef int (*ut_sl_match_callback)(const UT_SL_NODE *node, void *arg);

/**
用于指定链表排序方式的回调函数的原型

如果如果此函数按照节点 pNode1 中某个值小于 pNode2 中某个值，
并且返回非0值的方式进行处理的话，那么链表中的节点将按照从小到大的顺序排列；

如果如果此函数按照节点 pNode1 中某个值大于 pNode2 中某个值，
并且返回非0值的方式进行处理的话，那么链表中的节点将按照从大到小的顺序排列；

@param [in] pNode1: 指向链表中的一个节点
@param [in] pNode2: 指向链表中的一个节点
@return 返回非0值，则将交换节点 pNode1 和节点 pNode2 的位置。
        返回0值，则不交换
*/
typedef int (*ut_sl_sort_callback)(const UT_SL_NODE *pNode1, const UT_SL_NODE *pNode2);







/* 全局变量声明区 ----------------------------------------------------------- */







/* 全局函数声明区 ----------------------------------------------------------- */


/**
********************************************************************************
@brief    静态链表头初始化
@details  本函数用于将 sl 指向的的链表置为空链表。
@param[out]  sl: 指向要初始化的链表头。
@retval  none
@note 如果 sl 指向的链表为非空链表，那么在执行本函数后，链表中节点就丢失了
@warning  sl 不能为 NULL
@see sllist_alloc_init()
*/
static inline void ut_sllist_static_init(UT_SL_LIST *sl)
{
    UT_SLLIST_INIT(sl);
}


extern void     ut_sllist_cleanup(UT_SL_LIST *sl, ut_sl_trav_callback callback);
extern uint32_t ut_sllist_isempty(const UT_SL_LIST *sl);
extern uint32_t ut_sllist_length(const UT_SL_LIST *sl);
extern int32_t  ut_sllist_insert_head(UT_SL_LIST *sl, UT_SL_NODE *node);
extern int32_t  ut_sllist_insert_tail(UT_SL_LIST *sl, UT_SL_NODE *node);
extern UT_SL_NODE *ut_sllist_at(const UT_SL_LIST *sl, uint32_t index);
extern UT_SL_NODE *ut_sllist_find(const UT_SL_LIST *sl, ut_sl_match_callback callback,
                            void *arg);
extern int32_t  ut_sllist_delete(UT_SL_LIST *sl, const UT_SL_NODE *node);







/** addtogroup SIGNAL_LINK_LIST
 * @}
 */

#ifdef __cplusplus
}
#endif
#endif /* !__SIGNAL_LINK_LIST_H__ */


/********************************** END OF FILE *******************************/
